package venndiagram;

import java.awt.Point;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Adam
 */
public class GraphDataThreeSets implements GraphData
{
    public String aName;
    public String bName;
    public String cName;

    public int a;
    public int b;
    public int c;
    public int ab;
    public int ac;
    public int bc;
    public int abc;

    public CircleData maxCircle;
    public CircleData midCircle;
    public CircleData minCircle;
    public final double MAX_RADIUS;

    public GraphDataThreeSets(String aName, String bName, String cName, int a, int b, int c, int ab, int ac, int bc, int abc)
    {
        //Set Names
        this.aName = aName;
        this.bName = bName;
        this.cName = cName;

        //Number of elements in each subset
        this.a = a;
        this.b = b;
        this.c = c;
        this.ab = ab;
        this.ac = ac;
        this.bc = bc;
        this.abc = abc;

        //Get total number of elements in each set
        int aTotal = a + ab + ac + abc;
        int bTotal = b + ab + bc + abc;
        int cTotal = c + ac + bc + abc;

        //Initialize max, mid and min circles; set max radius
        if(aTotal >= bTotal && aTotal >= cTotal)
        {
            //Create maxCircle based on set a
            MAX_RADIUS = Math.sqrt(aTotal / Math.PI);
            this.maxCircle = new CircleData(MAX_RADIUS, new Point(0,0), this.aName);
            //Create mid and min circles based on sets b and c, respectively
            if(bTotal >= cTotal)
            {
                this.midCircle = new CircleData(Math.sqrt(bTotal / Math.PI), new Point(0,0), this.bName);
                this.minCircle = new CircleData(Math.sqrt(cTotal / Math.PI), new Point(0,0), this.cName);
            }
            //Create mid and min circles based on sets c and b, respectively
            else
            {
               this.midCircle = new CircleData(Math.sqrt(cTotal / Math.PI), new Point(0,0), this.cName);
               this.minCircle = new CircleData(Math.sqrt(bTotal / Math.PI), new Point(0,0), this.bName); 
            }
        }
        else if(bTotal >= cTotal)
        {
            //Create maxCircle based on set b
            MAX_RADIUS = Math.sqrt(bTotal / Math.PI);
            this.maxCircle = new CircleData(MAX_RADIUS, new Point(0,0), this.bName);
            //Create mid and min circles based on sets a and c, respectively
            if(aTotal >= cTotal)
            {
                this.midCircle = new CircleData(Math.sqrt(aTotal / Math.PI), new Point(0,0), this.aName);
                this.minCircle = new CircleData(Math.sqrt(cTotal / Math.PI), new Point(0,0), this.cName);
            }
            //Create mid and min circles based on sets c and a, respectively
            else
            {
               this.midCircle = new CircleData(Math.sqrt(cTotal / Math.PI), new Point(0,0), this.cName);
               this.minCircle = new CircleData(Math.sqrt(aTotal / Math.PI), new Point(0,0), this.aName);
            }
        }
        else
        {
            //Create maxCircle based on set c
            MAX_RADIUS = Math.sqrt(cTotal / Math.PI);
            this.maxCircle = new CircleData(MAX_RADIUS, new Point(0,0), this.cName);
            //Create mid and min circles based on sets a and b, respectively
            if(aTotal >= bTotal)
            {
                this.midCircle = new CircleData(Math.sqrt(aTotal / Math.PI), new Point(0,0), this.aName);
                this.minCircle = new CircleData(Math.sqrt(bTotal / Math.PI), new Point(0,0), this.bName);
            }
            //Create mid and min circles based on sets b and a, respectively
            else
            {
               this.midCircle = new CircleData(Math.sqrt(bTotal / Math.PI), new Point(0,0), this.bName);
               this.minCircle = new CircleData(Math.sqrt(aTotal / Math.PI), new Point(0,0), this.aName);
            }
        }
    }


    @Override
    //Find and set centers for all three circles
    public void findCenters()
    {
        double intToMax;    //Ratio of intersection between max and mid circles to max circle

        //Use intersection of sets a and b for ratio
        if((maxCircle.getName().equals(this.aName)) && (midCircle.getName().equals(this.bName) ||
          (maxCircle.getName().equals(this.aName)) && (midCircle.getName().equals(this.bName))))
            intToMax = ab / (MAX_RADIUS * MAX_RADIUS * Math.PI);

        //Use intersection of sets a and c for ratio
        else if((maxCircle.getName().equals(this.aName)) && (midCircle.getName().equals(this.bName) ||
          (maxCircle.getName().equals(this.aName)) && (midCircle.getName().equals(this.bName))))
            intToMax = ac / (MAX_RADIUS * MAX_RADIUS * Math.PI);

        //Use intersection of sets b and c for ration
        else
            intToMax = bc / (MAX_RADIUS * MAX_RADIUS * Math.PI);

        //Initialize distance so the circles don't intersect
        int distance = (int) (maxCircle.getRadius() + midCircle.getRadius() + 1);

        double intersection;    //Area of intersection of max and mid circles

        //Decrease distance until area of intersection at current distance is greater than previously calculated area of intersection
        do
        {
            distance--;
            intersection = findIntersection(maxCircle.getRadius(), midCircle.getRadius(), distance);
        }
        while(intersection / (MAX_RADIUS * MAX_RADIUS * Math.PI) < intToMax);

        //TODO Check if intersection from distance + 1 is more accurate than current distance

        //Set midCircle center
        midCircle.setCenter(new Point(0, (int)distance));

        //TODO Calculate center for minCircle
    }

    //Find the area of intersection for two circles
    public double findIntersection(double radius1, double radius2, int distance)
    {
        return (radius1 * radius1 * Math.acos((distance * distance + radius1 * radius1 - radius2 * radius2) / (2 * distance * radius1))) +
               (radius2 * radius2 * Math.acos((distance * distance + radius2 * radius2 - radius1 * radius1) / (2 * distance * radius2))) -
               (0.5 * Math.sqrt((radius1 + radius2 - distance) * (radius1 - radius2 + distance) * (radius2 - radius1 + distance) * (radius1 + radius2 + distance)));
    }

}
